package com.iatinspur.learn2;

import com.iatinspur.pojo.Student;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 *
 *  第6集-10集 常见内存溢出代码 1-6种
 *  todo 1.equals()和hashCode()
 *       2.内部类应用外部内
 *       3.ThreadLocal的使用    没有池一般不会
 *       4.String的intern方法
 *       5.通过静态字段保存对象
 *       6.资源没有正常关闭       没有池一般不会
 */
public class Learn_2_JVM {

    public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();

    public String name="Learn_2_JVM";

    public static long count = 0;

    public static Map<Student,Long> map = new HashMap<Student,Long>();

    public static List<Inner> list = new ArrayList<Inner>();

    public static List<Inner2> list2 = new ArrayList<Inner2>();

    public static List<Object> list3 = new ArrayList<Object>();

    /**
     * 这个线程 keepAliveTime=0 代表永久存活
     */
    public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Integer.MAX_VALUE,Integer.MAX_VALUE,0, TimeUnit.DAYS,new SynchronousQueue<Runnable>());



    public static void main(String[] args) throws InterruptedException, IOException {
        myTest6();
    }

    /**
     * 想不内存溢出 两个方法都必须修改
     * equals()和hashCode()
     * @throws InterruptedException
     */
    public static void myTest1() throws InterruptedException {
        while(true){
            if(count++ %1000 == 0){
                Thread.sleep(10);
            }
            Student student = new Student();
            student.setId(1);
            student.setName("张三");
            // hashcode 方法要改写 不然就撑爆了
            map.put(student,1L);
        }
    }


    /**
     * equals()和hashCode()
     * @throws InterruptedException
     */
    public static void hasTest() throws InterruptedException {
        HashSet<Student>set = new HashSet<>();
        Student student = new Student();
        student.setId(1);
        student.setName("张三");

        Student student1 = new Student();
        student1.setId(1);
        student1.setName("张三");

        Student student2 = new Student();
        student2.setId(1);
        student2.setName("张三");

        set.add(student);
        set.add(student1);
        set.add(student2);
        System.out.println(set);
    }

    private byte[] bytes = new byte[1024*1024];

    public class Inner{

    }

    public static class Inner2{

    }

    /**
     *  内部类引用外部类
     *  无static 内部类是要是引用外部类的。外部类要是够大 就是内存泄漏
     */
    public static void myTest2() {
        while(true){
            // todo 第一个内存溢出
            list.add(new Learn_2_JVM().new Inner());

            // todo 第二个就不会
            list2.add(new Learn_2_JVM.Inner2());

            // todo 原因：是第1个会 内存泄露
        }
    }


    /**
     * 匿名内部类 要是应用外部类（前提是引用，有可能不引用,代码决定，编译器自动给）
     */
    public void myTest3() {
       List<String> mylist=new ArrayList<String>(){
           private String a = "111";
           @Override
           public int hashCode() {
               System.out.println(name);
               return super.hashCode();
           }
       };

        mylist.hashCode();
    }


    /**
     * 这样其实是可能但未必内存溢出
     * 线程结束 是会被销毁的
     * @throws InterruptedException
     * @throws IOException
     */
    public static void myTest4() throws InterruptedException, IOException {
        System.out.println(1111);

    //    System.in.read();

       while(true){
           new Thread(()->{
               threadLocal.set(new byte[1024*1024*10]);
               System.out.println(threadLocal);
           }).start();
           Thread.sleep(10);

       }

    }



    /**
     * 池内数据是最大
     * 存活时间 无限大  这个就得内存溢出
     * @throws InterruptedException
     * @throws IOException
     */
    public static void myTest5() throws InterruptedException, IOException {
        System.out.println(1111);
        while(true){
            threadPoolExecutor.execute(()->{
                threadLocal.set(new byte[1024*1024*10]);
            });

        }

    }



    /**
     * 大量数据堆积到string常量池中
     * @throws InterruptedException
     * @throws IOException
     */
    public static void myTest6() throws InterruptedException, IOException {
        System.in.read();
        int count =0 ;
        while(true){
            // todo 这个根本没法回收
            list3.add( Integer.toHexString(count).intern());
            // todo 要是内存够大 还是有可能能回收的
            Integer.toHexString(count).intern();
            count++;

        }

    }










}
